package com.bobo.web.provider.config;

import com.alibaba.fastjson.JSONObject;
import com.bobo.web.api.vo.base.ResponseResult;
import com.bobo.web.provider.client.dingding.DingDingWarnClient;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.core.annotation.Order;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.UUID;

@Aspect
//@Order(-99) // 控制多个Aspect的执行顺序，越小越先执行,为了要在Spring的事务之后执行,所以给他设置99
@Order(1)
public class ControllerParamAOP {

    private static final Logger logger = LoggerFactory.getLogger(ControllerParamAOP.class);
    @Resource
    private DingDingWarnClient dingDingWarnClient;

    /**
     * 定义切点Pointcut
     * 第一个*号：表示返回类型， *号表示所有的类型
     * 第二个*号：表示类名，*号表示所有的类
     * 第三个*号：表示方法名，*号表示所有的方法
     * 后面括弧里面表示方法的参数，两个句点表示任何参数
     */
    @Pointcut("execution(* com.bobo.web.provider.controller..*.*(..))")
    public void executionService() {
    }

    /**
     * 方法之后调用
     *
     * @param joinPoint
     * @param returnValue 方法返回值
     */
    @AfterReturning(pointcut = "executionService()", returning = "returnValue")
    public void doAfterReturning(JoinPoint joinPoint, Object returnValue) {
        MDC.put("returnValue", returnValue + "");
        // 处理完请求，返回内容
        MDC.clear();
    }

    /**
     * 统计方法执行耗时Around环绕通知
     *
     * @param joinPoint
     * @return
     */
    @Around("executionService()")
    public Object timeAround(ProceedingJoinPoint joinPoint) {
        String requestId = String.valueOf(UUID.randomUUID());
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String ip = getRemoteHost(request);
        String url = request.getRequestURL().toString();
        MDC.put("requestId", requestId);
        MDC.put("url", url);
        MDC.put("ip", ip);
        MDC.put("param", Arrays.toString(joinPoint.getArgs()));
        logger.info("----方法" + joinPoint.getSignature().getName() + "开始----");
        //获取开始执行的时间
        long startTime = System.currentTimeMillis();
        // 定义返回对象、得到方法需要的参数
        Object obj = null;
        try {
            obj = joinPoint.proceed();
        } catch (Throwable e) {
            logger.error("方法：" + joinPoint.getSignature().getName(), e);
            sendErrorMessage(e);
            return ResponseResult.error("系统错误");
        }

        // 获取执行结束的时间
        long endTime = System.currentTimeMillis();
        // 打印耗时的信息
        MDC.put("spend", String.valueOf(endTime - startTime));
        logger.info("----方法" + joinPoint.getSignature().getName() + "结束----");
        return obj;
    }

    /**
     * 获取目标主机的ip
     *
     * @param request
     * @return
     */
    private String getRemoteHost(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

    private void sendErrorMessage(Throwable e) {

        JSONObject json = new JSONObject();
        json.put("msgtype", "text");
        JSONObject jsonContent = new JSONObject();
        JSONObject jsonData = new JSONObject();
        jsonData.put("dossier-server-requestId", MDC.get("requestId"));
        jsonData.put("url", MDC.get("url"));
        jsonData.put("errorMessage", e.toString());
        jsonContent.put("content", jsonData.toJSONString());
        json.put("text", jsonContent.toJSONString());
        dingDingWarnClient.sendAssignStudentReport(json.toJSONString());
    }
}
